#pragma once
#include<iostream>
#include<unordered_map>
#include<assert.h>
#include<vector>
#include<string.h>
#include<functional>
#include<sys/epoll.h>
#include<thread>
#include<mutex>
#include<sys/eventfd.h>
#include<memory>
#include<unistd.h>
#include <sys/timerfd.h>
#include"logger.hpp"

class Poller;
class EventLoop;
class Channel
{    
public:
    using EventCallback=std::function<void()>;
    Channel(int fd,EventLoop* event_loop):_fd(fd),_event(0),_revents(0),_event_loop(event_loop)/*_poller(poller)*/{}
    int FD(){return _fd;}
    uint32_t Revent(){return _revents;}
    //获取想要监控的事件
    uint32_t Events(){return _event;}
    //设置实际就绪的事件
    void SetRevents(uint32_t events){_revents=events;}
    /*可读事件被触发的回调函数*/
    void SetReadCallback(const EventCallback& cb){_read_callback=cb;}
    /*可写事件被触发的回调函数*/
    void SetWriteCallback(const EventCallback& cb){_write_callback=cb;}
    /*错误事件被触发的回调函数*/
    void SetErrorCallback(const EventCallback& cb){_error_callback=cb;}
    /*连接断开事件被触发的回调函数*/
    void SetCloseCallback(const EventCallback& cb){_close_callback=cb;}
    /*任意事件被触发的回调函数*/
    void SetEventCallback(const EventCallback& cb){_event_callback=cb;}
    /*当前是否监控了可读*/
    bool ReadAble(){return (_event&EPOLLIN);}
    /*当前是否监控了可写*/
    bool WriteAble(){return (_event&EPOLLOUT);}
    /*启动读事件监控*/
    void EnableRead(){_event|=EPOLLIN;Update();}
    /*启动写事件监控*/
    void EnableWrite(){_event|=EPOLLOUT;Update();}
    /*关闭读事件监控*/
    void DisableRead(){_event&=~EPOLLIN;Update();}
    /*关闭写事件监控*/
    void DisableWrite(){_event&=~EPOLLOUT;Update();}
    /*关闭所有事件监控*/
    void DisableAll(){_event=0;Update(); }
    /*移除监控*/
    void Remove();
    void Update();
    /*事件处理，一旦连接触发了事件，就调用这个函数*/
    void HandleEvent(){
        if((_revents&EPOLLIN)||(_revents&EPOLLRDHUP)||(_revents&EPOLLPRI)){
            /*不管任何事件，都调用的回调函数*/
            if(_event_callback) _event_callback();
            if(_read_callback)  _read_callback();
        }
        /*有可能会释放连接的操作事件，一次只处理一个*/
        if(_revents&EPOLLOUT){//调试发现这里使用if,如果写端关闭了，调用了可读事件，把channel关闭了，就还会进来这里，会导致调用里面任何一个，但是chanel已经没了，就会出现段错误
            // /*不管任何事件，都调用的回调函数*/
            if(_event_callback) _event_callback();//事件处理之后再调用，刷新活跃度，防止被释放
            if(_write_callback)  _write_callback();//进行写入的时候，发现连接断开了，写入出错了，就要释放套接字
        }
        else if(_revents&EPOLLERR){
            if(_event_callback) _event_callback();
            if(_error_callback)  _error_callback();//一旦出错了，就释放连接了，连接都释放了，就没必要去调用任意事件的回调了，因此要放在前面
        }
        else if(_revents&EPOLLHUP){
            if(_event_callback) _event_callback();
            if(_close_callback)  _close_callback();
        }
        
    }
    ~Channel(){
        _read_callback=nullptr;
        _write_callback=nullptr;
        _error_callback=nullptr;
        _close_callback=nullptr;
        _event_callback=nullptr;
        //DEBUG：这个根据不同的系统，默认情况下，
        // 调用Channel的默认析构函数中，对于成员函数不会置空，这里需要手动写一个Channel的析构函数，
        // 在析构函数中，将各种回调函数都置为nullptr--->解决客户端关闭，这里会访问已经释放的channel而导致的系统崩溃

    }
private:
    int _fd;
    uint32_t _event;//当前需要监控的事件
    uint32_t _revents;//当前连接触发的事件--监控之后实际触发的事件
    // Poller* _poller;//只是之前用来测试
    EventLoop* _event_loop;
    EventCallback _read_callback;
    EventCallback _write_callback;
    EventCallback _error_callback;
    EventCallback _close_callback;
    EventCallback _event_callback;
};





#define MAX_EPOLLEVENTS 1024
class Poller
{   
private:
    //对epoll进行操作，调用epoll_ctl，
    void Update(Channel* channel,int op){
        //int epoll_ctl(int epfd,int op,int fd,struct epoll_event *ev)
        int fd=channel->FD();
        struct epoll_event ev;
        ev.data.fd=fd;
        ev.events=channel->Events();
        int ret=epoll_ctl(_epfd,op,fd,&ev);
        if(ret<0){
            ELOG(" epollctl failed");
            abort();
        }
    }
    //判断一个channel是否已经添加了事件监控
    bool HasChannel(Channel* channel){
        auto it = _channels.find(channel->FD());
        if(it==_channels.end())return false;
        return true;
    }

public:
    Poller(){
        _epfd=epoll_create(88);
        if(_epfd<0){
            ELOG("epoll create failed");
            abort();
        }
    }
    /*添加或修改监控事件*/
    void UpdateEvent(Channel* channel){
        bool ret=HasChannel(channel);
        if(ret==false)  {
            _channels.insert(std::make_pair(channel->FD(),channel));
            return Update(channel,EPOLL_CTL_ADD);
        }
        return Update(channel,EPOLL_CTL_MOD);
    }
    /*移除监控*/
    void RemoveEvent(Channel* channel){
        auto it = _channels.find(channel->FD());
        if(it!=_channels.end()) //由于这里写成了等号，导致释放了一个空的，只要涉及移除，就会出错----好像又没出错了，奇怪，待定
            _channels.erase(it);
        Update(channel,EPOLL_CTL_DEL);
    }
    /*开始监控，返回活跃连接*/
    void Poll(std::vector<Channel*>*active){
        //int epoll_wait(int epfd,struct epoll_event *evs,int maxevents,int timout)
        //nfds就绪的事件个数
        int nfds=epoll_wait(_epfd,_evs,MAX_EPOLLEVENTS,-1);//使用阻塞监控，没有描述符就绪，就一直在这监控
        if(nfds<0){
            if(errno==EINTR) return;//如果是被信号打断了就直接返回，只是给信号打断了阻塞而已，可以继续监控下一次的
            ELOG("EPOLL WAIT ERROR:%s\n",strerror(errno));//如果是其他错误，无论是什么错误都会导致大量描述符无法进行事件监控处理
            abort(); 
        }
        for(int i=0;i<nfds;i++){
            auto it=_channels.find(_evs[i].data.fd);
            assert(it!=_channels.end());//按理来说，我能够获取到，我能够对一个描述符进行事件监控，能够就绪事件，那他必然存在于所管理的_channels里的
            //如果他不存在，描述符就绪了，但是又找不到channels信息，就是异常了，代表管理出现问题了
            it->second->SetRevents(_evs[i].events);
            active->push_back(it->second);
        }
    }
private:
    int _epfd;
    struct epoll_event _evs[MAX_EPOLLEVENTS];
    std::unordered_map<int,Channel*> _channels;
};

using TaskFunc=std::function<void()>;
using ReleaseFunc=std::function<void()>;
class TimerTask{
public:
    TimerTask(uint64_t id,uint32_t delay,const TaskFunc &cb)
    :_id(id),_timeout(delay),_task_cb(cb),_canceled(false){}
    ~TimerTask(){
        if(_canceled==false) _task_cb();
        _release();
    }
    void Cancel(){_canceled=true;}
    void SetRelease(const ReleaseFunc&cb){_release=cb;}
    uint32_t DelayTime(){return _timeout;}

private: 
    uint64_t _id;//定时器任务对象id
    uint32_t _timeout;//定时任务的超时时间
    bool _canceled;//false-表示没有被取消，true-表示被取消了
    TaskFunc _task_cb;//定时器对象要执行的定时任务
    ReleaseFunc _release;//用于删除TimerWheel中保存的定时器对象信息
};

using WeakTask = std::weak_ptr<TimerTask>;
using PtrTask = std::shared_ptr<TimerTask>;
class TimerWheel {
    private:
        void RemoveTimer(uint64_t id) {
            auto it = _timers.find(id);
            if (it != _timers.end()) {
                _timers.erase(it);
            }
        }
        static int TimerCreate(){
            int timerfd=timerfd_create(CLOCK_MONOTONIC,0);
            if(timerfd<0){
                ELOG("timerfd create failed");
                return -1;
            }
            //int timerfd_settime(int fd, int flags, struct itimerspec *new, struct itimerspec *old);
            struct itimerspec itime;
            itime.it_value.tv_sec=1;//第一次超时时间为1s后
            itime.it_value.tv_nsec=0;
            itime.it_interval.tv_sec=1;//第一次超时后，每次超时的间隔时间
            itime.it_interval.tv_nsec=0;
            timerfd_settime(timerfd,0,&itime,NULL);
            return timerfd;
        }
        void ReadTimerfd(){
            uint64_t timers;
            int ret =read(_timerfd,&timers,8);
            if(ret<0){
                perror("read timerfd failed");
                abort();
            }
        }
        //这个函数应该每秒钟被执行一次，相当于秒针向后走了一步
        void RunTimerTask() {
            _tick = (_tick + 1) % _capacity;
            _wheel[_tick].clear();//清空指定位置的数组，就会把数组中保存的所有管理定时器对象的shared_ptr释放掉
        }
        void OnTime(){
            ReadTimerfd();
            RunTimerTask();
        }
        void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &cb) {
        PtrTask pt(new TimerTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
        }
        //刷新/延迟定时任务
        void TimerRefreshInLoop(uint64_t id) {
            //通过保存的定时器对象的weak_ptr构造一个shared_ptr出来，添加到轮子中
            auto it = _timers.find(id);
            if (it == _timers.end()) {
                return;//没找着定时任务，没法刷新，没法延迟
            }
            PtrTask pt = it->second.lock();//lock获取weak_ptr管理的对象对应的shared_ptr
            int delay = pt->DelayTime();
            int pos = (_tick + delay) % _capacity;
            _wheel[pos].push_back(pt);
        }
        void TimerCancelInLoop(uint64_t id) {
            auto it = _timers.find(id);
            if (it == _timers.end()) {
                return;//没找着定时任务，没法刷新，没法延迟
            }
            PtrTask pt = it->second.lock();
            if (pt) pt->Cancel();
        }
    public:
        TimerWheel(EventLoop *loop):_capacity(60), _tick(0), _wheel(_capacity),_loop(loop)
        ,_timerfd(TimerCreate()),_timer_channel(std::make_unique<Channel>(_timerfd,_loop))
        {
            _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime,this));
            _timer_channel->EnableRead();//启动读事件监控：一秒钟就会触发一次读事件
        }
        /*定时器中有个_timers成员，定时器信息的操作有可能在多线程中进行，因此需要考虑线程安全问题*/
        /*如果不想加锁，那就把对定时器的所有操作，都放到一个线程中进行*/
        void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb);
        void TimerRefresh(uint64_t id);
        void TimerCancel(uint64_t id);
        /*这个接口存在线程安全问题，在调用的时候要注意不能在其他线程调用*/
        /*这个接口实际上不能被外界使用者调用，只能在模块内，在对应的EventLoop线程内调用执行*/
        bool HasTimer(uint64_t id){
            auto it = _timers.find(id);
            if (it == _timers.end()) {
                return false;
            }
            return true;
        }
    
    private:
        int _tick;      //当前的秒针，走到哪里释放哪里，释放哪里，就相当于执行哪里的任务
        int _capacity;  //表盘最大数量---其实就是最大延迟时间
        std::vector<std::vector<PtrTask>> _wheel;
        std::unordered_map<uint64_t, WeakTask> _timers;

        EventLoop *_loop;
        int _timerfd;//定时器描述符，一旦触发一次超时，读取一次定时器的数据，运行一次runtimertask，运行一次过期任务
        std::unique_ptr<Channel> _timer_channel;//--可读事件回调就是读取定时器，执行定时任务
};


using Functor=std::function<void()>;
class EventLoop{
public:
    /*执行任务池中的所有任务*/
    void RunAllTask(){
        //_tasks既然是操作任务池，就意味着任意一个地方都有可能去运行任务---->所以存在线程安全问题，要加锁
        std::vector<Functor> tasks_copy;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _tasks.swap(tasks_copy);
        }
        for(auto& task:tasks_copy){
            task();
        }
    }
    static int CreateEventfd(){
        int efd=eventfd(0,EFD_CLOEXEC|EFD_NONBLOCK);
        if(efd<0){
            ELOG("eventfd failed");
            return -1;
        }
        return efd;
    }
    void ReadEventfd(){
        uint64_t res=0;
        int ret =read(_event_fd,&res,sizeof(res));
        if(ret<0){
            //EINTR--被信号打断  EAGAIN--表示无数据可读
            if(errno==EINTR||errno==EAGAIN) return;
            ELOG("read eventfd failed");
            abort();
        }
    }
    void WakeupEventfd(){
         uint64_t val=1;
        int ret =write(_event_fd,&val,sizeof(val));
        if(ret<0){
            if(errno==EINTR) return;
            ELOG("wakeup eventfd failed");
            abort();
        }
    }
public:
    EventLoop()
        :_thread_id(std::this_thread::get_id())
        ,_event_fd(CreateEventfd())
        ,_event_channel(new Channel(_event_fd,this))
        ,_timer_wheel(this)
    {
        //给eventfd添加可读事件回调函数，读取eventfd事件通知次数
        _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd,this));
        //启动eventfd的读事件监控
        _event_channel->EnableRead();
    }
    /*启动三步走：事件监控->就绪事件处理->执行任务*/
    void Start(){
        while(1)
        {
            std::vector<Channel*> actives;
            _poller.Poll(&actives);
            for(auto& channel:actives)
                channel->HandleEvent();
            RunAllTask();
        } 
    }
    /*用于判断当前线程是否是EventLoop对应的线程*/
    bool IsThisLoop(){
        if(_thread_id==std::this_thread::get_id())return true;
        return false;
    }
    void AssertInLoop(){
        assert(_thread_id==std::this_thread::get_id());
    }
    /*判断将要执行的任务是否处于当前线程中，如果是则执行，如果不是则压入队列*/
    void RunLoop(const Functor& task){
        if(IsThisLoop())
            return task();
        return QueueInLoop(task);
    }
    /*将操作压入任务池*/
    void QueueInLoop(const Functor&task){
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _tasks.push_back(task);
        }
        //唤醒有可能因为没有事件就绪（就是没有事件，epool_wait会阻塞一直等）, 而导致的epoll阻塞；
        //其实就是给eventfd写入一个数据，eventfd就会触发可读事件
        WakeupEventfd();
    }
    /*添加/修改描述符的事件监控*/
    void UpdateEvent(Channel*channel){return _poller.UpdateEvent(channel);}
    /*移除描述符的监控*/
    void RemoveEvent(Channel*channel){return _poller.RemoveEvent(channel);}
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb){
        _timer_wheel.TimerAdd(id,delay,cb);
    }
    void TimerRefresh(uint64_t id){_timer_wheel.TimerRefresh(id);}
    void TimerCancel(uint64_t id){_timer_wheel.TimerCancel(id);}
    bool HasTimer(uint64_t id){return _timer_wheel.HasTimer(id);}
private:
    std::thread::id _thread_id;//线程id
    int _event_fd;//enventfd唤醒IO事件监控有可能导致的阻塞
    std::unique_ptr<Channel> _event_channel;
    Poller _poller;//进行所有描述符的事件监控
    std::vector<Functor> _tasks;//任务池
    std::mutex _mutex;//实现任务池操作的线程安全
    TimerWheel _timer_wheel;//定时器模块
};
// void Channel::Remove(){return _poller->RemoveEvent(this);}
// void Channel::Update(){return _poller->UpdateEvent(this);}
void Channel::Remove(){return _event_loop->RemoveEvent(this);}//已经在event_loop模块封装事件监控poller
void Channel::Update(){return _event_loop->UpdateEvent(this);}


void TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb){
    _loop->RunLoop(std::bind(&TimerWheel::TimerAddInLoop,this,id,delay,cb));
}

void TimerWheel::TimerRefresh(uint64_t id) {
    _loop->RunLoop(std::bind(&TimerWheel::TimerRefreshInLoop,this,id));
}

void TimerWheel::TimerCancel(uint64_t id) {
    _loop->RunLoop(std::bind(&TimerWheel::TimerCancelInLoop,this,id));
}